package javaer.starter.idea.util;

import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.intellij.ide.highlighter.JavaFileType;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ModifiableRootModel;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.vfs.*;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiJavaFile;
import com.intellij.psi.PsiManager;
import com.intellij.psi.search.FileTypeIndex;
import com.intellij.psi.search.GlobalSearchScope;
import javaer.starter.constants.SymbolEnum;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.idea.maven.project.MavenProject;
import org.jetbrains.idea.maven.project.MavenProjectsManager;

import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import static javaer.starter.JavaerStarter.JAVAER_STARTER_TEMPLATE;

/**
 * @author yangzhen
 * @date 2023/7/4 15:06
 * @since 1.0.0
 */
public class IdeaUtils {

    /**
     * 获取java文件的公共包前缀
     *
     * @param
     * @return
     */
    public static String getCommonPackagePrefix(Map<String, List<PsiFile>> psiFileMap) {
        List<PsiJavaFile> javaFiles = new ArrayList<>();
        psiFileMap.forEach(
                (k, v) -> {
                    v.forEach(vs -> {
                        if (vs instanceof PsiJavaFile) {
                            javaFiles.add(((PsiJavaFile) vs));
                        }
                    });
                }
        );

        // 如果没有Java文件，则返回空字符串
        if (javaFiles.isEmpty()) {
            return "";
        }

        // 获取第一个Java文件的包
        String commonPrefix = javaFiles.get(0).getPackageName();

        // 遍历所有Java文件，找到公共包前缀
        for (int i = 1; i < javaFiles.size(); i++) {
            String packageName = javaFiles.get(i).getPackageName();

            // 比较当前Java文件的包和前面Java文件的公共包前缀
            while (!packageName.startsWith(commonPrefix)) {
                // 缩短公共前缀直到二者匹配
                commonPrefix = commonPrefix.substring(0, commonPrefix.length() - 1);
                // 如果公共前缀为空，则说明没有公共包前缀
                if (commonPrefix.isEmpty()) {
                    return "";
                }
            }
        }

        if (commonPrefix.endsWith(SymbolEnum.POINT.getSymbol())) {
            commonPrefix = commonPrefix.substring(0, commonPrefix.length() - 1);
        }

        return commonPrefix;
    }

    /**
     * 通过module获取各自的java文件
     *
     * @param project
     * @return
     */
    public static Map<String, List<PsiJavaFile>> getJavaFilesByModule(Project project) {
        Module[] modules = getModules(project);
        PsiManager psiManager = PsiManager.getInstance(project);
        Map<String, List<PsiJavaFile>> result = new HashMap<>();
        for (Module module : modules) {
            Collection<VirtualFile> virtualFiles =
                    FileTypeIndex.getFiles(JavaFileType.INSTANCE, GlobalSearchScope.moduleScope(module));
            List<PsiJavaFile> javaFiles = new ArrayList<>();
            for (VirtualFile virtualFile : virtualFiles) {
                PsiJavaFile psiJavaFile = (PsiJavaFile) psiManager.findFile(virtualFile);
                if (psiJavaFile != null) {
                    javaFiles.add(psiJavaFile);
                }
            }
            result.put(module.getName(), javaFiles);
        }
        return result;
    }

    public static Set<PsiFile> getPsiFile(PsiManager psiManager, MavenProject mavenProject, Set<String> skipPath) {
        Set<PsiFile> result = new HashSet<>();
        // pom.xml
        VirtualFile moduleFile = mavenProject.getFile();
        if (moduleFile == null) {
            MessageUtils.notifyInfo("IdeaUtils.getPsiFile is empty for " + mavenProject.getName());
            return result;
        }
        VirtualFile parent = moduleFile.getParent();
        VfsUtilCore.visitChildrenRecursively(parent, new VirtualFileVisitor<Object>() {
            @Override
            public boolean visitFile(@NotNull VirtualFile file) {

                // 过滤pom.xml文件
                if (file.getPath().equals(moduleFile.getPath())) {
                    return false;
                }

                // 过滤文件名，如：module.iml
                if (skipPath.contains(file.getName())) {
                    return false;
                }

                // 过滤已知文件夹
                if (skipPath.contains(file.getPath())) {
                    return false;
                }

                // 过滤空的文件夹
                if (file.isDirectory() && (file.getChildren() == null || file.getChildren().length == 0)) {
                    return false;
                }

                // 过滤target文件
                if (file.isDirectory() && file.getPath().equals(parent.getPath() + SymbolEnum.SLASH.getSymbol() + SymbolEnum.TARGET.getSymbol())) {
                    return false;
                }

                // 过滤/src/test/resources文件
                if (file.isDirectory() && file.getPath().equals(parent.getPath() + SymbolEnum.SLASH.getSymbol() + SymbolEnum.SRC_TEST_RESOURCES.getSymbol())) {
                    return false;
                }

                // 过滤/src/test/java文件
                if (file.isDirectory() && file.getPath().equals(parent.getPath() + SymbolEnum.SLASH.getSymbol() + SymbolEnum.SRC_TEST_JAVA.getSymbol())) {
                    return false;
                }

                // 过滤内置的目录
                if (file.isDirectory() && file.getPath().equals(parent.getPath() + SymbolEnum.SLASH.getSymbol() + JAVAER_STARTER_TEMPLATE)) {
                    return false;
                }

                File localFile = VfsUtilCore.virtualToIoFile(file);
                if (localFile.isHidden()) {
                    return false;
                }
                if (localFile.isFile()) {
                    PsiFile psiFile = psiManager.findFile(file);
                    result.add(psiFile);
                }
                return true;
            }
        });
        return result;
    }

    public static Map<String, List<PsiFile>> getPsiFileByModule(Project project) {

        PsiManager psiManager = PsiManager.getInstance(project);

        MavenProjectsManager mavenProjectsManager = MavenProjectsManager.getInstance(project);

        List<MavenProject> rootMavenProjects = getRootMavenProjects(project);
        MavenProject rootMavenProject = rootMavenProjects.get(0);

        Set<String> skipPaths = new HashSet<>();
        // pom.xml
        Set<String> modulePaths = rootMavenProject.getModulePaths();
        skipPaths.add(rootMavenProject.getPath());
        skipPaths.addAll(modulePaths);

        LocalFileSystem localFileSystem = LocalFileSystem.getInstance();
        List<MavenProject> mavenProjects = new ArrayList<>();
        for (String modulePath : modulePaths) {
            VirtualFile vf = localFileSystem.findFileByPath(modulePath);
            MavenProject mavenProject = mavenProjectsManager.findProject(vf);
            mavenProjects.add(mavenProject);
        }

        // 结果
        Map<String, List<PsiFile>> result = new HashMap<>();

        for (MavenProject mavenProject : mavenProjects) {
            Set<PsiFile> modulePsiFileSet = getPsiFile(psiManager, mavenProject, Sets.newHashSet(mavenProject.getPath()));
            result.put(mavenProject.getName(), Lists.newArrayList(modulePsiFileSet));
            // module目录
            skipPaths.add(mavenProject.getFile().getParent().getPath());
            // module.iml
            skipPaths.add(mavenProject.getName() + ".iml");
        }

        Set<PsiFile> psiFileSet = getPsiFile(psiManager, rootMavenProject, skipPaths);
        result.put(rootMavenProject.getName(), Lists.newArrayList(psiFileSet));
        return result;
    }

    /**
     * 获取project对应的所有maven模块
     * MavenProject#isAggregator判断当前模块是否是root
     *
     * @param project
     * @return
     */
    public static List<MavenProject> getMavenProjects(Project project) {
        return MavenProjectsManager.getInstance(project).getProjects();
    }

    /**
     * 获取project下的所有maven的根模块
     *
     * @param project
     * @return
     */
    public static List<MavenProject> getRootMavenProjects(Project project) {
        return MavenProjectsManager.getInstance(project).getRootProjects();
    }

    /**
     * 获取maven项目的模块
     *
     * @param project
     * @return
     */
    public static Module[] getModules(Project project) {
        return ModuleManager.getInstance(project).getModules();
    }

    /**
     * 获取maven项目的模块模型
     *
     * @param module
     * @return
     */
    public static ModifiableRootModel getModuleModel(Module module) {
        return ModuleRootManager.getInstance(module).getModifiableModel();
    }

    /**
     * 获取模块依赖的模块
     *
     * @param moduleModel
     * @return
     */
    public static Module[] getModuleDependencies(ModifiableRootModel moduleModel) {
        return moduleModel.getModuleDependencies();
    }

    /**
     * 获取模块依赖的模块
     *
     * @param module
     * @return
     */
    public static Module[] getModuleDependencies(Module module) {
        return getModuleModel(module).getModuleDependencies();
    }

    public static MavenProject getMavenProject(Project project, Module module) {
        return getMavenProject(null, project, module);
    }

    public static MavenProject getMavenProject(MavenProjectsManager mavenProjectsManager, Project project, Module module) {
        if (mavenProjectsManager == null) {
            mavenProjectsManager = MavenProjectsManager.getInstance(project);
        }
        return mavenProjectsManager.findProject(module);
    }
}
